package net.iceflow.dunsel.commons.commandqueue;

import java.util.EnumMap;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;

/**
 *
 */
public abstract class AbstractCommandQueue<K extends Enum<K>, T> implements CommandQueueContext {

    private final EnumMap<K, Command<CommandQueueContext<T>>> _commandMap;
    private final Queue<K> _commandAliasQueue = new LinkedBlockingQueue<K>();
    private final T _model;

    /**
     * Constructs a new CommandQueue.
     * @param clazz
     */
    public AbstractCommandQueue(final Class clazz, T model) {
        this._commandMap = new EnumMap<K, Command<CommandQueueContext<T>>>(clazz);
        this._model = model;
    }

    public void addCommand(K commandAlias) {
        if (this._commandMap.containsKey(commandAlias)) {
            this._commandAliasQueue.add(commandAlias);
        }
    }

    public boolean executeNext() {

        synchronized (this._commandAliasQueue) {
            if (this._commandAliasQueue.isEmpty()) {
                return false;
            }

            K commandAlias = this._commandAliasQueue.poll();

            Command<CommandQueueContext<T>> command = this._commandMap.get(commandAlias);
            command.execute(this);
        }

        return true;
    }

    @Override
    public T getModel() {
        return this._model;
    }

    /**
     * Registers a command for a key
     * @param key
     * @param command
     */
    public void registerCommand(K key, Command<CommandQueueContext<T>> command) {
        this._commandMap.put(key, command);
    }

    public void unregisterCommand(K key) {
        this._commandMap.remove(key);
    }

    public void unregisterAll() {
        this._commandMap.clear();
    }

    public void clearQueue() {
        this._commandAliasQueue.clear();
    }
}
